import json
import time
from selenium import webdriver
from selenium.webdriver.edge.service import Service
from selenium.webdriver.edge.options import Options
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from lxml import etree
import csv
from function_utils import scroll_to_bottom,scroll_up,scroll_down,scroll_up_and_down


url='https://www.taobao.com/'

#   指定浏览器驱动的位置
service=Service(r"D:\py_pycharm\pythonProject\CompetitionData\msedgedriver.exe")
#   初始化edge浏览器的设置
options=Options()
options.add_argument('--disable-blink-features=AutomationControlled')  # 关闭自动化提示
#   驱动实例化
driver=webdriver.Edge(service=service,options=options)

# 执行脚本隐藏 `navigator.webdriver`      为了避免被认成自动化程序
driver.execute_script("Object.defineProperty(navigator, 'webdriver', {get: function() { return undefined }});")

#   这里之所以要先进入到这个网页再加载cookie是因为，如果先加载cookie的话，再打开浏览器，cookies会被刷新掉
#   所以需要先打开浏览器再加载cookie然后再跳转到需要爬取数据的网页
driver.get(url)



"""
5. 总结
driver.execute_cdp_cmd：通过 CDP 向浏览器发送命令，执行低层次的操作。
'Page.addScriptToEvaluateOnNewDocument'：在每个新加载的页面上注入并执行指定的 JavaScript 代码。
delete navigator.__proto__.webdriver：删除 navigator 对象原型链中的 webdriver 属性，使浏览器看起来不是由自动化工具
控制的。
通过这一方法，开发者能够绕过某些反自动化机制，确保 Selenium 脚本能够更加顺利地执行，尤其是在那些对 navigator.webdriver 属
性敏感的网站上。
"""
driver.execute_cdp_cmd('Page.addScriptToEvaluateOnNewDocument', {
    'source': 'delete navigator.__proto__.webdriver',
})

#   读取cookies
with open('cookies.json','r',encoding='utf-8') as file:
    cookies=file.read()

#       对读取的cookies进行处理
cookie_list=cookies.split("\n")
#   因为根据\n换行之后会存在一行是空值，所以下面选择元素的时候就需要淘汰掉最后一行
for x in range(0,len(cookie_list)-1):
    # print(cookie_list[x])
    #   先将每一行cookie转化成字典，方便处理
    dict_cookie=json.loads(cookie_list[x])
    #   cookie_list['expiry']存的是cookies的时间戳，由于存的是上次保存到本地的时间戳，现在已经过期了，所以要换成
    #   当前时间戳还要往后面一些的时间戳才可以,并且是以秒为单位的而不是毫秒,time.time()得到是一个以秒为单位的
    dict_cookie['expiry']=int(time.time()+3600)
    #   将每一条cookie添加到driver
    driver.add_cookie(dict_cookie)

time.sleep(3)
#   打开淘宝的首页
driver.get(url)

#   刷新网页,在加载了cookie之后就必须要刷新网页，这样cookie才可以生效
driver.refresh()
#   将网页最大化
driver.maximize_window()
time.sleep(5)

m=0
#   根据网页的结构依次点击进入爬取数据
for x in range(1,12):
    if x != 2:
        for j in range(1, 5):
            time.sleep(3)
            #  点击要爬取的标签类
            driver.find_element(
                By.XPATH,
                '//*[@id="ice-container"]/div[2]/div[2]/div[2]/div[1]/div/ul/li[' + str(x) + ']/div[1]/a[' + str(
                    j) + ']'
            ).click()

            #   驱动跳转到刚刚点击的商品页面
            driver.switch_to.window(driver.window_handles[-1])
            time.sleep(3)

            # 等待页面加载并且所有的图片加载完毕，不加载完毕的话滑到底部就会存在很多空数据
            WebDriverWait(driver, 20).until(
                lambda driver: driver.execute_script("""
                    return Array.from(document.images).every(img => img.complete && img.naturalWidth > 0);
                """)
            )

            # 滚动到底部
            driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
            time.sleep(5)

            #   再上下滑动一遍，以获取更多的数据
            scroll_up_and_down(driver)
            #   再划到顶部，因为网页结构发生了改变
            scroll_up(driver)

            try:
                #   查看当前是进入到了哪一大类
                search_class = driver.find_element(By.XPATH, '//*[@id="q"]').get_attribute("value")
                print(search_class, "类开始爬取数据")
            except Exception:
                print("遇到了报错")
                #   关闭当前网页
                driver.close()
                #   更改驱动所在的网页，这样就回到首页了
                driver.switch_to.window(driver.window_handles[-1])
                continue

            #   爬取数据过程
            #  获取html源码
            html_str=driver.page_source
            # print(html_str)
            #   将字符串的htnl转化为可以使用xpath的实例
            html=etree.HTML(html_str)


            #   存储每一行的数据
            row_list=[]
            n = 0
            # input('卡死先')
            #   由于我们是每个大类的商品选取5个，所以下面用循环
            for k in range(1,21):

                title_list = []
                price_list = []
                address_list = []
                buy_number_list = []
                shop_name_list = []
                image_url_list = []
                info_url_list=[]



                #   商品的标题
                title=html.xpath(
                    #   第一条是最开始的xpath路径，后面发生了改变网页结构
                    '//*[@id="search-content-leftWrap"]/div[3]/div[3]/div/a['+str(k)+']/div/div[1]/div[2]/div/span/text()'
                    # '//*[@id="search-content-leftWrap"]/div[2]/div[3]/div/div['+str(k)+']/a/div/div[1]/div[2]/div/span/text()'

                )
                print(title)
                #   商品的价格   要注意的是这里的是如果是div/text()那就只会拿到div标签里面的内容，而不可以拿到div下面两个span标签里面的
                #   的内容，想要拿到div下面的两个span标签里面的内容就要div//span/text()
                price=html.xpath(
                    '//*[@id="search-content-leftWrap"]/div[3]/div[3]/div/a['+str(k)+']/div/div[1]/div[4]/div[1]//span/text()'
                    # '//*[@id="search-content-leftWrap"]/div[2]/div[3]/div/div['+str(k)+']/a/div/div[1]/div[4]/div[1]//span/text()'

                )
                print(price)
                #   商品的地区
                address=html.xpath(
                    '//*[@id="search-content-leftWrap"]/div[3]/div[3]/div/a['+str(k)+']/div/div[1]/div[4]//div[@class="procity--wlcT2xH9"]//span/text()',
                    # '//*[@id="search-content-leftWrap"]/div[2]/div[3]/div/div['+str(k)+']/a/div/div[1]/div[4]/div[2]/span/text()'
                )
                #   已经付款的人数
                buy_number=html.xpath(
                    '//*[@id="search-content-leftWrap"]/div[3]/div[3]/div/a['+str(k)+']/div/div[1]/div[4]/span[2]/text()',
                   # '//*[@id="search-content-leftWrap"]/div[2]/div[3]/div/div['+str(k)+']/a/div/div[1]/div[4]/span[2]/text()'
                )

                #   店铺的名称
                shop_name=html.xpath(
                    '//*[@id="search-content-leftWrap"]/div[3]/div[3]/div/a['+str(k)+']/div/div[3]/div[1]/a/div/span[2]/text()'
                    # '//*[@id="search-content-leftWrap"]/div[2]/div[3]/div/div['+str(k)+']/a/div/div[3]/div[1]/a/div/span/text()'
                )

                #   图片的url
                image_url=html.xpath(
                    '//*[@id="search-content-leftWrap"]/div[3]/div[3]/div/a['+str(k)+']/div/div[1]/div[1]/img/@src'
                    # '//*[@id="search-content-leftWrap"]/div[2]/div[3]/div/div['+str(k)+']/a/div/div[1]/div[1]/img[1]/@src'
                )

                #   商品详细信息的url
                info_url=html.xpath(
                    '//*[@id="search-content-leftWrap"]/div[3]/div[3]/div/a['+str(k)+']/@href'
                    # '//*[@id="search-content-leftWrap"]/div[3]/div[3]/div/div['+str(k)+']/a/@href'
                )

                #   这里做一个判断，如果所有字段拿到的值都是空值，就换一套xpath路径,总共有三套xpath路径
                if len(title)==0 and len(price)==0 and len(address)==0 and len(buy_number)==0:
                    #   商品的标题
                    title = html.xpath(
                        #   第一条是最开始的xpath路径，后面发生了改变网页结构
                        # '//*[@id="search-content-leftWrap"]/div[3]/div[3]/div/a[' + str(k) + ']/div/div[1]/div[2]/div/span/text()'
                        '//*[@id="search-content-leftWrap"]/div[2]/div[3]/div/div['+str(k)+']/a/div/div[1]/div[2]/div/span/text()'

                    )
                    print(title)
                    #   商品的价格   要注意的是这里的是如果是div/text()那就只会拿到div标签里面的内容，而不可以拿到div下面两个span标签里面的
                    #   的内容，想要拿到div下面的两个span标签里面的内容就要div//span/text()
                    price = html.xpath(
                        # '//*[@id="search-content-leftWrap"]/div[3]/div[3]/div/a[' + str(
                        #     k) + ']/div/div[1]/div[4]/div[1]//span/text()'
                        '//*[@id="search-content-leftWrap"]/div[2]/div[3]/div/div['+str(k)+']/a/div/div[1]/div[4]/div[1]//span/text()'

                    )
                    print(price)
                    #   商品的地区
                    address = html.xpath(
                        # '//*[@id="search-content-leftWrap"]/div[3]/div[3]/div/a[' + str(
                        #     k) + ']/div/div[1]/div[4]//div[@class="procity--wlcT2xH9"]//span/text()',
                        '//*[@id="search-content-leftWrap"]/div[2]/div[3]/div/div['+str(k)+']/a/div/div[1]/div[4]/div[2]/span/text()'
                    )
                    #   已经付款的人数
                    buy_number = html.xpath(
                        # '//*[@id="search-content-leftWrap"]/div[3]/div[3]/div/a[' + str(
                        #     k) + ']/div/div[1]/div[4]/span[2]/text()',
                        '//*[@id="search-content-leftWrap"]/div[2]/div[3]/div/div['+str(k)+']/a/div/div[1]/div[4]/span[2]/text()'
                    )

                    #   店铺的名称
                    shop_name = html.xpath(
                        # '//*[@id="search-content-leftWrap"]/div[3]/div[3]/div/a[' + str(
                        #     k) + ']/div/div[3]/div[1]/a/div/span[2]/text()'
                        '//*[@id="search-content-leftWrap"]/div[2]/div[3]/div/div['+str(k)+']/a/div/div[3]/div[1]/a/div/span/text()'
                    )

                    #   图片的url
                    image_url = html.xpath(
                        # '//*[@id="search-content-leftWrap"]/div[3]/div[3]/div/a[' + str(
                        #     k) + ']/div/div[1]/div[1]/img/@src'
                        '//*[@id="search-content-leftWrap"]/div[2]/div[3]/div/div['+str(k)+']/a/div/div[1]/div[1]/img[1]/@src'
                    )

                    #   商品详细信息的url
                    info_url = html.xpath(
                        # '//*[@id="search-content-leftWrap"]/div[3]/div[3]/div/a[' + str(k) + ']/@href'
                        '//*[@id="search-content-leftWrap"]/div[3]/div[3]/div/div['+str(k)+']/a/@href'
                    )
                    #   还是空值的情况下使用第三套xpath路径
                    if len(title) == 0 and len(price) == 0 and len(address) == 0 and len(buy_number) == 0:
                        #   商品的标题
                        title = html.xpath(
                            #   第一条是最开始的xpath路径，后面发生了改变网页结构
                            # '//*[@id="search-content-leftWrap"]/div[3]/div[3]/div/a[' + str(k) + ']/div/div[1]/div[2]/div/span/text()'
                            # '//*[@id="search-content-leftWrap"]/div[2]/div[3]/div/div[' + str(
                            #     k) + ']/a/div/div[1]/div[2]/div/span/text()'
                            '//*[@id="search-content-leftWrap"]/div[3]/div[3]/div/div[' + str(
                                k) + ']/a/div/div[1]/div[2]/div/span/text()'

                        )
                        print(title)
                        #   商品的价格   要注意的是这里的是如果是div/text()那就只会拿到div标签里面的内容，而不可以拿到div下面两个span标签里面的
                        #   的内容，想要拿到div下面的两个span标签里面的内容就要div//span/text()
                        price = html.xpath(
                            # '//*[@id="search-content-leftWrap"]/div[3]/div[3]/div/a[' + str(
                            #     k) + ']/div/div[1]/div[4]/div[1]//span/text()'
                            # '//*[@id="search-content-leftWrap"]/div[2]/div[3]/div/div[' + str(
                            #     k) + ']/a/div/div[1]/div[4]/div[1]//span/text()'
                            '//*[@id="search-content-leftWrap"]/div[3]/div[3]/div/div[' + str(
                                k) + ']/a/div/div[1]/div[4]/div[1]//span/text()'
                        )
                        print(price)
                        #   商品的地区
                        address = html.xpath(
                            # '//*[@id="search-content-leftWrap"]/div[3]/div[3]/div/a[' + str(
                            #     k) + ']/div/div[1]/div[4]//div[@class="procity--wlcT2xH9"]//span/text()',
                            # '//*[@id="search-content-leftWrap"]/div[2]/div[3]/div/div[' + str(
                            #     k) + ']/a/div/div[1]/div[4]/div[2]/span/text()'
                            '//*[@id="search-content-leftWrap"]/div[3]/div[3]/div/div[' + str(
                                k) + ']/a/div/div[1]/div[4]/div[2]/span/text()'
                        )
                        #   已经付款的人数
                        buy_number = html.xpath(
                            # '//*[@id="search-content-leftWrap"]/div[3]/div[3]/div/a[' + str(
                            #     k) + ']/div/div[1]/div[4]/span[2]/text()',
                            '//*[@id="search-content-leftWrap"]/div[3]/div[3]/div/div[' + str(
                                k) + ']/a/div/div[1]/div[4]/span[2]/text()'
                        )

                        #   店铺的名称
                        shop_name = html.xpath(
                            # '//*[@id="search-content-leftWrap"]/div[3]/div[3]/div/a[' + str(
                            #     k) + ']/div/div[3]/div[1]/a/div/span[2]/text()'
                            # '//*[@id="search-content-leftWrap"]/div[2]/div[3]/div/div[' + str(
                            #     k) + ']/a/div/div[3]/div[1]/a/div/span/text()'
                            '//*[@id="search-content-leftWrap"]/div[3]/div[3]/div/div[' + str(
                                k) + ']/a/div/div[3]/div[1]/a/div/span/text()'
                        )

                        #   图片的url
                        image_url = html.xpath(
                            # '//*[@id="search-content-leftWrap"]/div[3]/div[3]/div/a[' + str(
                            #     k) + ']/div/div[1]/div[1]/img/@src'
                            # '//*[@id="search-content-leftWrap"]/div[2]/div[3]/div/div[' + str(
                            #     k) + ']/a/div/div[1]/div[1]/img[1]/@src'
                            '//*[@id="search-content-leftWrap"]/div[3]/div[3]/div/div[' + str(
                                k) + ']/a/div/div[1]/div[1]/img[1]/@src'
                        )

                        #   商品详细信息的url
                        info_url = html.xpath(
                            # '//*[@id="search-content-leftWrap"]/div[3]/div[3]/div/a[' + str(k) + ']/@href'
                            # '//*[@id="search-content-leftWrap"]/div[3]/div[3]/div/div[' + str(k) + ']/a/@href'
                            '//*[@id="search-content-leftWrap"]/div[3]/div[3]/div/div[' + str(k) + ']/a/@href'
                        )

                #   下面判断拿到的数据是否为空值
                # n=0
                # while True:
                #     if len(title) or len() == 0:
                #         if n == 2:
                #             break
                #         print("读取的元素为空值了")
                #         scroll_up_and_down(driver)
                #         scroll_to_bottom(driver)
                #         title = html.xpath(
                #             '//*[@id="search-content-leftWrap"]/div[3]/div[3]/div/a[' + str(
                #                 k) + ']/div/div[1]/div[2]/div/span/text()'
                #         )
                #         n=n+1
                #     else:
                #         break

                #   标题
                # print("商品的标题")
                # print(title)
                if len(title)==0:
                    title=['空值']
                title_list.append(":".join(str(x) for x in title))      #   将列表里面所有元素用冒号分隔开连接起来

                #   价格
                # print("商品的价格")
                # print(price)
                if len(price)==0:
                    price=['空值']
                price_list.append("".join(str(x) for x in price))

                #   地区
                # print("商品的地区")
                # print(address)
                if len(address)==0:
                    address=['空值']
                address_list.append("".join(address))


                #   已经付款的人数
                # print("已经付款的人数")
                # print(buy_number)
                if len(buy_number)==0:
                    buy_number=['空值']
                buy_number_list.append("".join(buy_number))

                #   店铺的名称
                # print("店铺的名称")
                # print(shop_name)
                if len(shop_name)==0:
                    shop_name=['空值']
                shop_name_list.append("".join(shop_name))

                #   商品图片的url
                # print("商品图片的url")
                # print(image_url)
                if len(image_url)==0:
                    image_url=['空值']
                image_url_list.append(image_url[0])

                #   商品详细信息的url
                if len(info_url)==0:
                    info_url=['空值']
                info_url_list.append(info_url[0])
                print("**************************该商品爬完了**********************************")
                if m!=0:
                    #  将一行数据合并   字段为:type_id,product_id,
                    row_list.append(
                        [m, search_class, ((m + 1) * 10) + n , title_list[0],
                         price_list[0], address_list[0], buy_number_list[0], shop_name_list[0], image_url_list[0],info_url_list[0]]
                    )
                else:
                    row_list.append(
                        [m, search_class, (m*10)+n, title_list[0],
                         price_list[0], address_list[0], buy_number_list[0], shop_name_list[0], image_url_list[0],info_url_list[0]]
                    )
                n = n + 1
            m =  m + 1
            #  打印每一行的数据
            for y in row_list:
                print(y)
            #   将数据写入到文件
            with open('source.csv','a',newline='',encoding='utf-8') as file:
                #   创建csv写入对象
                write=csv.writer(file)
                #   写入数据
                write.writerows(row_list)



            print("-------------------------------",search_class,"类爬完了--------------------------------------------")
            #   爬完了当页关闭当前网页
            driver.close()
             #   更改驱动所在的网页，这样就回到首页了
            driver.switch_to.window(driver.window_handles[-1])





#   设置如下代码的话必须要在控制台回车才会执行下面的代码
input("请在控制台回车关闭网页")

# driver.quit()